﻿using System;
using UnityEngine.Networking;
using System.Collections;
using UnityEngine;
using System.IO;
using Aliyun.OSS;
using Aliyun.OSS.Common;

namespace ZyGame.Transport
{
    public class UploadHandle
    {
        public string filePath;
        public UploadState state;
        public float progres = 0f;
        private string md5;
        private int reCount = 0;
        private string fileName;
        private string remotePath;
        private UploadConfig address;
        private byte[] fileData = Array.Empty<byte>();
        private OssClient oss;

        public UploadHandle(string path, UploadConfig config)
        {
            filePath = path;
            address = config;
            fileName = Path.GetFileName(filePath);
            remotePath = $"{AppConfig.GetPlatformName().ToLower()}/{fileName}";
            switch (address.service)
            {
                case Service.OSS:
                    var _configuration = new ClientConfiguration();
                    _configuration.ConnectionTimeout = 10000;
                    oss = new OssClient(address.url, address.pid, address.sid, _configuration);
                    break;
            }
        }

        public bool TryUpload()
        {
            return reCount < 5;
        }

        public IEnumerator OnStart()
        {
            if (reCount > 5)
            {
                ChangeState(UploadState.Failurefuly);
                yield break;
            }

            reCount++;
            fileData = File.ReadAllBytes(filePath);
            md5 = fileData.GetMd5();
            switch (address.service)
            {
                case Service.OSS:
                    try
                    {
                        PutObjectResult result = oss.PutObject(address.name, remotePath, File.OpenRead(filePath));
                        Client.Console.WriteLineFormat("Put object:{0} succeeded", result.ETag);
                    }
                    catch (OssException ex)
                    {
                        
                        Client.Console.WriteErrorFormat("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",
                            ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
                    }
                    catch (Exception ex)
                    {
                        Client.Console.WriteErrorFormat("Failed with error info: {0}", ex);
                    }

                    break;
                case Service.NONE:
                    yield return RequestDeleteFile();
                    break;
            }
        }

        private IEnumerator RequestDeleteFile()
        {
            using UnityWebRequest request = UploadApi.RequestDelete(address, md5, remotePath);
            yield return request.SendWebRequest();
            if (!EnsureWebRequestState(request))
            {
                ChangeState(UploadState.Failurefuly);
                yield break;
            }

            Client.Console.WriteLine("Delete Remote File:" + remotePath, request.downloadHandler.text);
            yield return OnRequestCreateFile();
        }

        private IEnumerator OnRequestCreateFile()
        {
            using UnityWebRequest request = UploadApi.RequestCreate(address, remotePath, md5, fileData.Length);
            yield return request.SendWebRequest();
            if (!EnsureWebRequestState(request))
            {
                ChangeState(UploadState.Failurefuly);
                yield break;
            }

            yield return OnStartUpload(request.downloadHandler.text, fileData);
        }

        private IEnumerator OnStartUpload(string content, byte[] bytes)
        {
            using UnityWebRequest request = UploadApi.RequestUpload(content, bytes);
            if (request is null)
            {
                ChangeState(UploadState.Failurefuly);
                yield break;
            }

            request.SendWebRequest();
            while (!request.isDone)
            {
                progres = request.uploadProgress;
                yield return new WaitForSeconds(0.03f);
            }

            if (!EnsureWebRequestState(request))
            {
                ChangeState(UploadState.Failurefuly);
                yield break;
            }

            progres = 1;
            yield return RequestDoneUpload();
        }

        private IEnumerator RequestDoneUpload()
        {
            using UnityWebRequest request = UploadApi.RequestDone(address, remotePath);
            yield return request.SendWebRequest();
            if (!EnsureWebRequestState(request))
            {
                ChangeState(UploadState.Failurefuly);
                yield break;
            }

            ChangeState(UploadState.Successfuly);
            Client.Console.WriteLine($"Upload Completion:{filePath}");
        }

        private bool EnsureWebRequestState(UnityWebRequest request)
        {
            if (request == null || request.result is not UnityWebRequest.Result.Success)
            {
                Client.Console.WriteError(request?.error + "\n" + request?.downloadHandler.text);
                return false;
            }

            return true;
        }

        private void ChangeState(UploadState state)
        {
            this.state = state;
        }
    }
}